<!DOCTYPE html>
<html>
	<head>
		<title>管道设备模型展示，下雨，下雪，阴天，晴天，火焰</title>
		<meta http-equiv="Pragma" content="no-cache" />
		<meta http-equiv="Cache-Control" content="no-cache" />
		<meta http-equiv="Expires" content="0" />
		<script type="text/javascript" src="libs/three.js"></script>
		<script type="text/javascript" src="libs/OrbitControls.js"></script>
		<script type="text/javascript" src="libs/OBJLoader.js"></script>
		<script type="text/javascript" src="libs/Tween.min.js"></script>
		<script type="text/javascript" src="libs/dat.gui.js"></script>

		<!-- <script type="text/javascript" src="libs/EffectComposer.js"></script>
		<script type="text/javascript" src="libs/RenderPass.js"></script>
		<script type="text/javascript" src="libs/OutlinePass.js"></script>
		<script type="text/javascript" src="libs/ShaderPass.js"></script>
		<script type="text/javascript" src="libs/FXAAShader.js"></script> -->
		<style>
			body {
				margin: 0;
				overflow: hidden;
			}
			.panel{
				position: absolute;
				width: 100px;
				height: 100px;
				background: #fff;
				overflow: hidden; 
				z-index: 9999; 
			}
		</style>
	</head>
	<body>
		<div id="dom"></div>
		<script type="text/javascript">
			var camera;
			var renderer;
			var cloud;
			var rainy_sw = 3; // 1雨2雪3晴4阴
			var flame_sw = true;
			//初始化一个空容器，装载粒子
			var krq = new THREE.Object3D();
			var textureLoader = new THREE.TextureLoader();
			var group3 = new THREE.Group();
			var cuurrentObj = null
			// hover 发光配置
			var composer = null
			var outlinePass = null
			var renderPass = null


			function init() {
				// 创建一个场景，它将包含我们所有的元素，如物体，相机和灯光。
				var scene = new THREE.Scene();

				var urls = [
					'assets/textures/posx.webp',
					'assets/textures/negx.webp',
					'assets/textures/posy.webp',
					'assets/textures/negy.webp',
					'assets/textures/posz.webp',
					'assets/textures/negz.webp'
				];
				var urls1 = [
					'assets/textures/posx_gray.webp',
					'assets/textures/negx_gray.webp',
					'assets/textures/posy_gray.webp',
					'assets/textures/negy_gray.webp',
					'assets/textures/posz_gray.webp',
					'assets/textures/negz_gray.webp'
				];

				var cubeLoader = new THREE.CubeTextureLoader();
				scene.background = cubeLoader.load(urls);

				// 创建一个摄像机，它定义了我们正在看的地方
				camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 0.1, 20000);
				// 将摄像机对准场景的中心
				camera.position.x = 180;
				camera.position.y = 80;
				camera.position.z = 90;
				camera.lookAt(scene.position);
				// 轨道控制器
				var orbit = new THREE.OrbitControls(camera);

				// 创建一个渲染器并设置大小，WebGLRenderer将会使用电脑显卡来渲染场景
				renderer = new THREE.WebGLRenderer({
					antialias: true, // 是否执行抗锯齿
					logarithmicDepthBuffer: true, // 是否使用对数深度缓存
				});
				renderer.setClearColor(new THREE.Color(0x121A39)); // 设置颜色及其透明度
				renderer.setSize(window.innerWidth, window.innerHeight);
				var alight = new THREE.AmbientLight("#ffffff", 1); // 环境光会均匀的照亮场景中的所有物体。
				alight.name = "aLight";
				scene.add(alight);

				// 在屏幕上显示坐标轴
				var axes = new THREE.AxesHelper(100);
				// scene.add(axes);

				// 将平面添加到场景中
				createPlaneGeometryBasicMaterial();
				creatRoadSurface();
				crateWall();

				createTankPipeMaterial()
				createMonitorCamerasMaterial()
				createPipeLineMaterial()
				createValvesMaterial()

				// 创建各种设备
				createInstrumentMaterial()
				createThermometerMaterial()
				createPowerSwitchMaterial()
				createCubeMaterial()
				createTelescopeMaterial()
				createTubeMaterial()
				createSpeakerMaterial()
				createHelicopterMaterial()

				// 双击事件
				addEventListener('dblclick', onMouseDblclick, false);
				// hover事件
				addEventListener('mousemove', onMousemoveEvent, false);

				// 将呈现器的输出添加到HTML元素
				document.getElementById("dom").appendChild(renderer.domElement);

				// 使用GUI调试库
				var controls = new function() {
					this.rainy = function() {
						scene.remove(scene.getObjectByName("particles_snowy"));
						if (rainy_sw != 1) {
							rainy_sw = 1;
							scene.background = cubeLoader.load(urls1);
							scene.getObjectByName("aLight").intensity = 0.6;
							createPointRainy();
						}
					}

					this.snowy = function() {
						scene.remove(scene.getObjectByName("particles_rainy"));
						if (rainy_sw != 2) {
							rainy_sw = 2;
							scene.background = cubeLoader.load(urls1);
							scene.getObjectByName("aLight").intensity = 2;
							createPointRainy();
						}
					}

					this.sunny = function() {
						if (rainy_sw != 3) {
							scene.remove(scene.getObjectByName("particles_rainy"));
							scene.remove(scene.getObjectByName("particles_snowy"));
							scene.background = cubeLoader.load(urls);
							scene.getObjectByName("aLight").intensity = 1.2;
							rainy_sw = 3;
						}

					}

					this.cloudy = function() {
						if (rainy_sw != 4) {
							scene.remove(scene.getObjectByName("particles_rainy"));
							scene.remove(scene.getObjectByName("particles_snowy"));
							scene.background = cubeLoader.load(urls1);
							scene.getObjectByName("aLight").intensity = 1;
							rainy_sw = 4;
						}
					}

					this.flame = function() {
						if (flame_sw) {
							initFlame();
							flame_sw = !flame_sw;
						}
					}
				}

				var gui = new dat.GUI();

				gui.add(controls, 'rainy'); // 雨
				gui.add(controls, 'snowy'); // 雪
				gui.add(controls, 'sunny'); // 晴
				gui.add(controls, 'cloudy'); // 阴
				gui.add(controls, 'flame'); // 火焰

				// 启动动画
				renderScene();

				function createPointRainy() {
					var img = rainy_sw == 1 ? "raindrop.webp" : rainy_sw == 2 ? "snowflake.webp" : "";
					var name = rainy_sw == 1 ? "particles_rainy" : rainy_sw == 2 ? "particles_snowy" : "";
					var texture = new THREE.TextureLoader().load("assets/textures/" + img);
					var geom = new THREE.Geometry();

					var material = new THREE.PointsMaterial({
						size: 1.5,
						transparent: true, // 是否设置透明度
						opacity: 1, // 透明
						map: texture, // 粒子材质
						blending: THREE.AdditiveBlending,
						sizeAttenuation: true, // 是否相同尺寸
						color: 0xffffff
					});

					var range = 350;
					for (var i = 0; i < 3500; i++) {
						var particle = new THREE.Vector3(
							Math.random() * range - range / 2,
							Math.random() * range * 1.5,
							1 + (i / 10 - 180)
						)
						if (rainy_sw == 2) {
							// 定义雨滴以多快的速度落下,纵向运动速度的范围是0.1～0.3
							particle.velocityY = (0.1 + Math.random() / 5) - 0.1;
							// 定义粒子（雨滴）如何水平移动,横向运动速度的范围是-0.16～+0.16
							particle.velocityX = ((Math.random() - 0.5) / 3) - 0.05;
						} else {
							particle.velocityY = 0.15 + Math.random() / 5;
							particle.velocityX = (Math.random() - 0.5) / 3;
						}
						geom.vertices.push(particle);
					}

					cloud = new THREE.Points(geom, material);
					cloud.sortParticles = true;
					cloud.name = name;
					scene.add(cloud);
				}

				// 添加火焰
				function initFlame() {
					var texture = new THREE.TextureLoader().load("assets/textures/flamex.webp");
					//sprite材质
					var material = new THREE.SpriteMaterial({
						//以canvas作为纹理
						map: texture,
						//混合度 加法混合
						blending: THREE.AdditiveBlending
					});

					//循环1000  添加粒子
					for (var i = 0; i < 2000; i++) {
						var particle = new THREE.Sprite(material);
						initParticle(particle, i);
						krq.add(particle);
						krq.name = "particles_flame";
					}
					scene.add(krq);
				}

				/**
				 * 粒子 延迟发散
				 * @param particle
				 * @param delay
				 */
				function initParticle(particle, delay) {
					particle.position.set(0, Math.random() + 12, 0);
					particle.scale.x = particle.scale.y = Math.random() * 13;
					//下面是一系列的动画
					var xx = Math.random() * 40 - 20;
					var yy = Math.cos((Math.PI / 100) * xx) * 80;
					//位移
					new TWEEN.Tween(particle.position)
						.delay(delay)
						.to({
							x: xx,
							y: yy,
							z: Math.random() * 40 - 20
						}, 2000)
						.onComplete(function() {
							initParticle(particle, delay);
						})
						.start();
					// 大小
					new TWEEN.Tween(particle.scale)
						.delay(delay)
						.to({
							x: 0.01,
							y: 0.01
						}, 1000)
						.start();
				}


				// 创建tank_pipe
				function createTankPipeMaterial() {
					var objLoader = new THREE.OBJLoader();
					// 定义一个[x, z]的坐标集，调整位置  0: 小立罐 1: 卧罐 2：立罐  3 四罐
					// var positions = [[0,0],[0,0],[0,0],[-100,-50],[-100,-50]]
					var positions = [[-42,170],[-71,112],[20,-20],[-85,-185],[-150,-90]]
					var scales = [[20,20,20], [10,10,22], [32,32,32], [15,15,15], [20,20,20]]
					objLoader.load('assets/models/tank_pipe/tank_pipe.obj', function(obj) {
						var meshs = obj.children;
						meshs.forEach((mesh, i) => {
							if (![0, 1, 2, 3].includes(i)) {
								return
							}
							// 给模型添加自定义属性，用于交互事件的判断
							mesh.serialNum = `oil_tank_${i+1}`
							mesh.material = new THREE.MeshBasicMaterial({
								map: new THREE.TextureLoader().load( `assets/models/tank_pipe/tank_pipe_${i+1}.webp`),
							});
							console.log(`tank_pipe${i+1}`, mesh)
							mesh.scale.set(scales[i][0], scales[i][1], scales[i][2]);
							mesh.position.set(11, 0, -85);
							var mc = mesh.clone();
							mc.translateX(positions[i][0]);
							mc.translateZ(positions[i][1]);
							scene.add(mc);
						})
					});
				}

				// 创建监控摄像头
				function createMonitorCamerasMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/monitor_camera/monitor_camera.obj', function(obj) {
						console.log('monitor_camera', obj)
						var meshs = obj.children;
						var mesh = obj.children[0];
						mesh.material = new THREE.MeshBasicMaterial({
							map: new THREE.TextureLoader().load('assets/models/monitor_camera/monitor_camera.webp'),
						});
						mesh.scale.set(15, 25, 15);
						mesh.position.set(11, 0, -85);

						// [x偏移量，z偏移量， Y旋转量]
						var positions = [[70, 212, Math.PI/4 * 3], [70, 125, Math.PI/4 * 5], [-25, 212, Math.PI/4 * 1], [-25, 125, Math.PI/4 * -1], [-65, 235, Math.PI/2], [-25, 35, Math.PI/2 * -1]]

						for (let i = 0; i < 6; i++) {
								mesh.nickName = `monitor_camera_${i+1}`
								var mc = mesh.clone();
								mc.translateX(positions[i][0]);
								mc.translateZ(positions[i][1]);
								mc.rotateY(positions[i][2]) // Math.PI/2
								scene.add(mc);
						}
					});
				}

				// 创建管道
				function createPipeLineMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/pipe_line/pipeline_finally.obj', function(obj) {
						console.log('pipe_line', obj)
						var meshs = obj.children;
						for(var i=0; i < 3; i++){
							var mesh = meshs[i];
							mesh.name = `pipe_line_${i+1}`
							mesh.material = new THREE.MeshBasicMaterial({
								map: new THREE.TextureLoader().load('assets/models/pipe_line/pipe_line.webp'),
								// color: new THREE.Color( '#8888ac' )
							});
							var mc = mesh.clone();
							mc.scale.set(7.5, 7.5, 7.5);
							mc.translateX(38);
							mc.translateY(5);
							mc.translateZ(73);
							mc.rotateY(Math.PI/2)
							mc.rotateZ(Math.PI/2)
							scene.add(mc);
						}
					});
				}

				// 创建阀门
				function createValvesMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/gate_valve/Gate_Valve.obj', function(obj) {
						console.log('Gate_Valve', obj)
						var meshs = obj.children;
						var positions = [[73, 78], [78, 73], [68, 83], [-85.3, -75],[-94, -75],[-85.3, 82],[-30, 130]]
						for(var i=0;i<2;i++){
							var mesh = obj.children[i];
							for(var j = 0; j< 7; j++){
								mesh.name = `valves_${j+1}`
								mesh.material = new THREE.MeshBasicMaterial({
									map: new THREE.TextureLoader().load('assets/models/gate_valve/GateValveAlbedo.webp'),
								});
								mesh.scale.set(2, 2, 2);
								mesh.position.set(positions[j][0], 6.5, positions[j][1]);
		
								var mc = mesh.clone();
								scene.add(mc);
							}
						}
					});
				}

				/**
				 * 创捷各种设备：
				 * 液体压力计、液位计、流量计、气体压力计、气体浓度计、
				 * 液位开关
				 * 温度传感器、湿度传感器
				 * 沉降仪、倾角仪
				 */

				// 温度计
				function createThermometerMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/thermometer/Thermometer.obj', function(obj) {
						console.log('Thermometer2', obj)
						var meshs = obj.children;
						var mesh = obj.children[0];
						mesh.material = new THREE.MeshBasicMaterial({
							map: new THREE.TextureLoader().load('assets/models/thermometer/Thermometer_basecolor.webp'),
						});
						mesh.scale.set(200, 200, 200);
						mesh.position.set(100, 30, -50);
						mesh.rotateY(Math.PI/4)
						var mc = mesh.clone();
						scene.add(mc);
					});
				}

				// 开关
				function createPowerSwitchMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/switch/Electro.obj', function(obj) {
						console.log('power_switch', obj)
						var meshs = obj.children;
						var mesh = obj.children[0];
						mesh.material = new THREE.MeshBasicMaterial({
							map: new THREE.TextureLoader().load('assets/models/switch/Electrical panel.webp'),
						});
						// mesh.scale.set(1, 1, 1);
						mesh.position.set(50, 15, -50);
						mesh.rotateY(Math.PI/4)
						var mc = mesh.clone();
						scene.add(mc);
					});
				}

				// 气体浓度计
				function createCubeMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/cube/Cube.obj', function(obj) {
						console.log('cube', obj)
						var meshs = obj.children;
						var mesh = obj.children[0];
						mesh.material = new THREE.MeshBasicMaterial({
							map: new THREE.TextureLoader().load('assets/models/cube/Texture_Col.webp'),
						});
						mesh.scale.set(5, 5, 5);
						mesh.position.set(80, 5, -30);
						mesh.rotateY(Math.PI/4)
						var mc = mesh.clone();
						scene.add(mc);
					});
				}

				// 仪器一
				function createInstrumentMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/instrument/OBJ.obj', function(obj) {
						console.log('instrument', obj)
						var meshs = obj.children;
						for(var i=0;i<16;i++){
							var mesh = obj.children[i];
							mesh.material = new THREE.MeshBasicMaterial({
								map: new THREE.TextureLoader().load('assets/models/instrument/Diffuse.webp'),
							});
							// mesh.scale.set(5, 5, 5);
							mesh.position.set(70, 5, -60);
							mesh.rotateY(Math.PI/4)
							var mc = mesh.clone();
							scene.add(mc);
						}
					});
				}

				// 仪器二
				function createTelescopeMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/telescope/telescope.obj', function(obj) {
						console.log('telescope', obj)
						var meshs = obj.children;
						for(var i=0;i<5;i++){
							var mesh = obj.children[i];
							mesh.material = new THREE.MeshBasicMaterial({
								map: new THREE.TextureLoader().load(`assets/models/telescope/textures/BaseColor-${i+1}.webp`),
							});
							mesh.scale.set(3, 3, 3);
							mesh.position.set(50, 5, -20);
							mesh.rotateY(Math.PI/4)
							var mc = mesh.clone();
							scene.add(mc);
						}
					});
				}

				// 仪器三
				function createTubeMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/tube/tube.obj', function(obj) {
						console.log('tube', obj)
						var meshs = obj.children;
						for(var i=0;i<5;i++){
							var mesh = obj.children[i];
							mesh.material = new THREE.MeshBasicMaterial({
								map: new THREE.TextureLoader().load(`assets/models/tube/textures/tube-${i+1}.webp`),
							});
							mesh.scale.set(0.3, 0.3, 0.3);
							mesh.position.set(80, 5, 0);
							mesh.rotateY(Math.PI/4)
							var mc = mesh.clone();
							scene.add(mc);
						}
					});
				}

				// 直升机
				function createHelicopterMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/Helicopter/Helicopter.obj', function(obj) {
						console.log('Helicopter', obj)
						var meshs = obj.children;
						for(var i=0;i<4;i++){
							var mesh = obj.children[i];
							mesh.material = new THREE.MeshBasicMaterial({
								map: new THREE.TextureLoader().load('assets/models/Helicopter/texture/Helicopter.webp'),
							});
							mesh.scale.set(0.1, 0.1, 0.1);
							mesh.position.set(20, 100, 90);
							mesh.rotateY(Math.PI * 2)
							var mc = mesh.clone();
							scene.add(mc);
						}
					});
				}

				// 仪器四 扬声器
				function createSpeakerMaterial() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/speaker/speaker.obj', function(obj) {
						console.log('speaker', obj)
						var meshs = obj.children;
						for(var i=0;i<15;i++){
							var mesh = obj.children[i];
							mesh.material = new THREE.MeshBasicMaterial({
								map: new THREE.TextureLoader().load(`assets/models/speaker/Texture/speaker/speaker-${i+1}.webp`),
							});
							mesh.scale.set(100, 100, 100);
							mesh.position.set(90, 5, 20);
							mesh.rotateY(Math.PI/4)
							var mc = mesh.clone();
							scene.add(mc);
						}
					});
				}

				/**
				 * 创建地面并添加材质
				 * wrapS属性定义的是纹理沿x轴方向的行为，而warpT属性定义的是纹理沿y轴方向的行为。
				 * Three.js为这些属性提供了如下两个选项：
				 * ·THREE.RepeatWrapping允许纹理重复自己。
				 * ·THREE.ClampToEdgeWrapping是属性的默认值。
				 * 属性值为THREE.ClampToEdgeWrapping时，那么纹理的整体不会重复，只会重复纹理边缘的像素来填满剩下的空间。
				 */
				function createPlaneGeometryBasicMaterial() {
					var cubeMaterial = new THREE.MeshStandardMaterial({
						map: textureLoader.load("assets/textures/tank_floor.webp"),
						transparent: true,
						side: THREE.DoubleSide,
					});
					// 创建地平面并设置大小
					var planeGeometry = new THREE.PlaneGeometry(230, 310);
					var plane = new THREE.Mesh(planeGeometry, cubeMaterial);

					// 设置平面位置并旋转
					plane.rotation.x = 0.5 * Math.PI;
					plane.rotation.y = Math.PI;
					plane.position.y = 0.1;
					scene.add(plane);
				}

				// 创建围栏
				function crateWall() {
					var objLoader = new THREE.OBJLoader();
					objLoader.load('assets/models/wall/wall.obj', function(obj) {
						obj.scale.set(1.21, 0.6, 1.192);
						var texLan = new THREE.TextureLoader().load('assets/models/wall/lan2.webp');
						// 纹理重复
						texLan.wrapS = THREE.RepeatWrapping;
						texLan.wrapT = THREE.RepeatWrapping;
						texLan.repeat.set(40, 1);
						obj.children[0].material = new THREE.MeshBasicMaterial({
							side: THREE.DoubleSide,
							map: texLan,
							transparent: true,
						});
						obj.children[1].material = new THREE.MeshBasicMaterial({
							map: new THREE.TextureLoader().load('assets/models/wall/door.webp'),
							side: THREE.DoubleSide,
							transparent: true,
						});
						scene.add(obj)
					});
				}

				function creatRoadSurface() {
					var textureLoader = new THREE.TextureLoader();
					var geometry = new THREE.PlaneGeometry(24, 310);
					var texture = textureLoader.load('assets/textures/road2.webp');
					texture.wrapS = THREE.RepeatWrapping;
					texture.wrapT = THREE.RepeatWrapping;
					texture.repeat.set(1, 10);
					var material = new THREE.MeshBasicMaterial({
						map: texture,
						side: THREE.DoubleSide,
					});
					var mesh = new THREE.Mesh(geometry, material);

					var positions = [[126.8, 0], [0, -166.8], [-126.8, 0], [0, 166.8]]
					for (let i = 0; i < 4; i++) {
						var mc = mesh.clone();
						mc.rotateX(-Math.PI / 2);
						if (i % 2 === 0) {
							mc.translateX(positions[i][0]);				
						} else {
							mc.rotateZ(Math.PI / 2);
							mc.translateX(positions[i][1]);
						}
						// mc.position.x = 105.5
						scene.add(mc);
					}
				}

				// 鼠标双击触发的方法
				function onMouseDblclick(event) {
					console.log('onMouseDblclick', event)
 
					// 获取 raycaster 和所有模型相交的数组，其中的元素按照距离排序，越近的越靠前
					var intersects = getIntersects(event);

					// 获取选中最近的 Mesh 对象
					if (intersects.length != 0 && intersects[0].object instanceof THREE.Mesh) {
							selectObject = intersects[0].object;
							console.log('selectObject', selectObject)
							// 此处调接口做后台交互，数据联调
							createPanel(selectObject.serialNum || selectObject.name, event)
							// changeMaterial(selectObject); // 改变mesh颜色
					} else {
							console.log("未选中 Mesh!");
					}
				}

				// 鼠标移动hover事件
				function onMousemoveEvent(event) {
					// console.log('mousemoveEvent', event)

					// 获取 raycaster 和所有模型相交的数组，其中的元素按照距离排序，越近的越靠前
					var intersects = getIntersects(event);

					// 清除上一个选中对象
					if (cuurrentObj) {
						cuurrentObj = null
					}
					// cuurrentObj
					// 	? cuurrentObj.color = 'red'
					// 	: (cuurrentObj = null);

					if (intersects.length) {
						// 处理选中的最上层对象
						if (intersects[0].object?.isMesh) {				
							cuurrentObj = intersects[0].object;
							console.log('cuurrentObj', cuurrentObj)
							cuurrentObj.color = 'green'
							// outlineObj(cuurrentObj)
						}
					}
				};

				function createPanel (name, event) {
					// 判断弹窗是否存在，先删除后创建
					var container = document.getElementById("dom")
					var preDom = document.getElementsByClassName('panel')[0]
					if (preDom) {
						preDom.remove()
					}
					var dom = document.createElement('div')
					var text = document.createTextNode(name)
					dom.appendChild(text)
					container.appendChild(dom)
					dom.className = 'panel'
					dom.style.left = `${event.clientX}px`
					dom.style.top = `${event.clientY - 100}px`
				}

				// 获取与射线相交的对象数组
				function getIntersects(event) {
					event.preventDefault();
					console.log("event.clientX:"+event.clientX)
					console.log("event.clientY:"+event.clientY)
	
					// 声明 raycaster 和 mouse 变量
					var raycaster = new THREE.Raycaster();
					var mouse = new THREE.Vector2();
	
					// 通过鼠标点击位置,计算出 raycaster 所需点的位置,以屏幕为中心点,范围 -1 到 1
					mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
					mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
	
					//通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
					raycaster.setFromCamera(mouse, camera);
	
					// 获取与射线相交的对象数组，其中的元素按照距离排序，越近的越靠前
					var intersects = raycaster.intersectObjects(scene.children);
	
					//返回选中的对象
					return intersects;
				}

				// 改变对象材质属性
				function changeMaterial(object) {
					var material = new THREE.MeshLambertMaterial({
							color: 0xffffff * Math.random(),
							transparent: object.material.transparent ? false : true,
							opacity: 0.8
					});
					object.material = material;
				}

				// 高亮显示模型（呼吸灯）
				function outlineObj (selectedObjects) {
					// 创建一个EffectComposer（效果组合器）对象，然后在该对象上添加后期处理通道。
					composer = new EffectComposer(renderer)
					// 新建一个场景通道  为了覆盖到原理来的场景上
					renderPass = new RenderPass(scene, camera)
					composer.addPass(renderPass);
					// 物体边缘发光通道
					outlinePass = new OutlinePass(new THREE.Vector2(window.innerWidth, window.innerHeight), scene, camera, selectedObjects)
					outlinePass.selectedObjects = selectedObjects
					outlinePass.edgeStrength = 10.0 // 边框的亮度
					outlinePass.edgeGlow = 1// 光晕[0,1]
					outlinePass.usePatternTexture = false // 是否使用父级的材质
					outlinePass.edgeThickness = 1.0 // 边框宽度
					outlinePass.downSampleRatio = 1 // 边框弯曲度
					outlinePass.pulsePeriod = 5 // 呼吸闪烁的速度
					outlinePass.visibleEdgeColor.set(parseInt(0x00ff00)) // 呼吸显示的颜色
					outlinePass.hiddenEdgeColor = new THREE.Color(0, 0, 0) // 呼吸消失的颜色
					outlinePass.clear = true
					composer.addPass(outlinePass)
					// 自定义的着色器通道 作为参数
					var effectFXAA = new ShaderPass(FXAAShader)
					effectFXAA.uniforms.resolution.value.set(1 / window.innerWidth, 1 / window.innerHeight)
					effectFXAA.renderToScreen = true
					composer.addPass(effectFXAA)
				}

				function renderScene() {
					orbit.update(); // 拖动
					TWEEN.update();

					if (cloud) {
						var vertices = cloud.geometry.vertices;
						vertices.forEach(function(v) {
							v.y = v.y - (v.velocityY);
							v.x = v.x - (v.velocityX);

							if (v.y <= 0) v.y = 60;
							if (v.x <= -20 || v.x >= 20) v.velocityX = v.velocityX * -0.8;
						});
						cloud.geometry.verticesNeedUpdate = true;
					}

					// 使用requestAnimationFrame函数进行渲染
					requestAnimationFrame(renderScene);
					renderer.render(scene, camera);
				}

				// 渲染的场景
				renderer.render(scene, camera);
				
				if (composer) {
					composer.render()
				}
			}
			window.onload = init;

			// 随着窗体的变化修改场景
			function onResize() {
				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();
				renderer.setSize(window.innerWidth, window.innerHeight);
			}
			// 监听窗体调整大小事件
			window.addEventListener('resize', onResize, false);
		</script>
	</body>
</html>
